// testing of the 'mine' card effect from dominion.c
// trash a treasure card from your hand and gain another treasure card in
// your hand costing up to 3 more

#include <stdio.h>
#include <stdlib.h>
#include "dominion.h"
#include "dominion_helpers.h"
#include "rngs.h"

#define MAX_CARD treasure_map

typedef struct gameState gameState;

//print the results of the testing
void print_results(int a, int b){
    double results = ((double)a) / b;
    printf("---------------------\n");
    printf("mine card effect -- %.f%% of test cases passed (%d/%d)\n", (results*100), a, b);
}

//sets all the values in the game struct to 0
void init_gamestate(struct gameState *g){
    int i;
    for(i = 0; i < sizeof(struct gameState); i++){
    	((char *)g)[i] = 0;
	}
}

int main(int argc, char **argv) {
    int i, j, k;
    int handCount, bonus, player;
    int expected_result, result, test_result;
    int temp, temp2, temp3, trashPos, trashCard, buy;
    int good_test, bad_test;
	int randomSeed, test_count;
    int t_loc[5], num_treasure;
    gameState g1, g2;
   
    if(argc != 3){
            printf("Usage: cardtest1 [seed] [number of tests]\n");
            return(0);
    }
   
    //initialize vars
    randomSeed = atoi(argv[1]);
    test_count = atoi(argv[2]);
    if(test_count < 0){
            printf("Please provide a positive integer for [number of tests]\n");
            return(0);
    }
    good_test = bad_test = 0;
   
    // set up random number
    SelectStream(1);
    PutSeed((long)randomSeed);
    
    for(i = 0; i<test_count; i++){
    	//create random inputs
    	init_gamestate(&g1);
		init_gamestate(&g2);
    	player = (int)(Random()*3)+1; //random player number
		g1.whoseTurn = g2.whoseTurn = player;
    	handCount = (int)(Random()*MAX_HAND); //random hand size
    	g1.handCount[player] = g2.handCount[player] = handCount;
    	//create a random hand with no treasure cards
    	for(j = 0; j < handCount; j++){
    		//keep picking until we get a non-treasure card
    		do{
    			temp = (int)(Random()*MAX_CARD);
    		}while(temp == copper || temp == silver || temp == gold);

    		g1.hand[player][j] = g2.hand[player][j] = temp;
    	}
    	
    	//pick the number of treasure cards to add to the hand
    	//this is less than handCount and less than 5
    	num_treasure = (int)(Random()*(handCount-1))%6;
    	
    	//add random treasure cards to hand in random places
    	for(j=0; j < num_treasure; j++){
    		do{
				temp3 = 0;
    			temp = (int)(Random()*(handCount-1)); //random location
    			//make sure it hasn't been picked before
    			for(k = 0; k < j; k++){
    				if(t_loc[k] == temp){
    					temp3 = 1;
    					break;
    				}
    			}
    		}while(temp3);
    		temp2 = (int)(Random()*2)+4; //random treasure card
    		g1.hand[player][temp] = g2.hand[player][temp] = temp2; //add to hand
    		t_loc[j] = temp; //store where the card is located
    	}

		expected_result = 0;
    	//pick which card to trash
    	//20% of the time, pick an incorrect card
    	if(i % 5 == 0){
    		expected_result = -1;
    		//half the time, pick a card outside the hand range
    		if(i % 10 == 0){
    			trashPos = (int)(Random()*9) + 1;
    			if(trashPos % 2 == 0){
    				trashPos *= -1; //make it a negative value half the time
    			}
    		}
    		//half the time, pick an incorrect card in-range
    		else{
    			do{
					temp = 0;
    				trashPos = (int)(Random()*(handCount)-1);
    				//make sure it's not in a treasure location
    				for(j = 0; j < num_treasure; j++){
    					if(trashPos == t_loc[j]){
    						temp = 1;
    						break;
    					}
    				}
    			}while(temp);
    		}
			trashCard = -1;
    	}
    	//80% of the time, pick one of our treasure locations
    	else{
    		expected_result = 0;
    		trashPos = t_loc[(int)(Random()*(num_treasure - 1))];
			trashCard = g1.hand[player][trashPos];
    	}
    	
    	//pick which card to buy
    	buy = (int)(Random()*2)+4;
    	
 		//see if this card is too expensive or not
 		if(getCost(trashCard) + 3 < getCost(buy)){
 			expected_result = -1;
 		}

		//20% of the time, pick a buy card that isn't a treasure card
		if (expected_result != -1){
			if ((i+1) % 5 == 0){
				expected_result = -1;
				while (buy == copper || buy == silver || buy == gold){
					buy = (int)(Random()*MAX_CARD);
				}
			}
		}

		//only do this if we've got a purchase that should pass so far
		if (expected_result != -1){
			//add treasure cards to the supply, but 10% of the time make them empty
			if (i % 10 != 0){
				g1.supplyCount[copper] = g2.supplyCount[copper] = 1;
				g1.supplyCount[silver] = g2.supplyCount[silver] = 1;
				g1.supplyCount[gold] = g2.supplyCount[gold] = 1;
			}
			else expected_result = -1;
		}
    	
    	//call the function
    	//add my mine card into the deck now
    	g1.hand[player][handCount] = g2.hand[player][handCount] = mine;
    	g1.handCount[player]++;
    	g2.handCount[player]++;
    	
    	result = cardEffect(mine, trashPos, buy, 0, &g1, handCount, NULL);
    	
    	//check results
    	if(expected_result != result){
    		if (expected_result == 0) printf("Error: function returned -1 when it should have succeeded!\n");
			else printf("Error: function returned 0 when it should have failed!\n");
    		bad_test++;
			continue;
    	}
		//if we expected a bad return from play_mine and got it, then we had a good test
		if(result == -1){
			good_test++;
			continue;
		}
	
		//make sure I have one more of the new card than I previously had
		test_result = 0;
		temp = temp2 = 0;
		for(j = 0; j < g1.handCount[player]; j++){
			if(g1.hand[player][j] == buy){
				temp++; //add 1 to temp if we find the buy card in g1
			}
		}
		for(j = 0; j < g2.handCount[player]; j++){
			if(g2.hand[player][j] == buy){
				temp2++;
			}
		}
		//compare the counts (should have 1 more buy card unless I bought what I trashed)
		if(temp2+1 != temp && buy != trashCard){
			printf("Error: the purchased card is not in hand!\n");
			test_result = -1;
		}
		//make sure the old card is trashed
		temp = temp2 = 0;
		for(j = 0; j < g1.handCount[player]; j++){
			if(g1.hand[player][j] == trashCard){
				temp++;
			}
		}
		for(j = 0; j < g2.handCount[player]; j++){
			if(g2.hand[player][j] == trashCard){
				temp2++;
			}
		}
		if(temp+1 != temp2 && buy != trashCard){
			printf("Error: trashed card is still in hand!\n");
			test_result = -1;
		}
		
		//make sure I have one less card
		else if(g1.handCount[player] != g2.handCount[player] - 1){
			printf("Error: hand has %d cards instead of %d!\n", g1.handCount[player], g2.handCount[player]-1);
			test_result = -1;
		}
		//make sure the card is in the played pile
		else if (g1.playedCards[g2.playedCardCount] != mine){
			printf("Error: mine card isn't in the discard pile!\n");
			test_result = -1;
		}

    	//determine if test passed or not
		if (test_result == -1) bad_test++;
		else good_test++;
    }

    //output the results
    print_results(good_test, test_count);
   
    return 0;
}
